

#include <cassert>
#include <cmath>
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
using namespace std;

using real_t = double;
struct Point {
  real_t p[3];
  real_t &operator[](int i) noexcept {
    assert(-1 < i && i < 3);
    return p[i];
  }
  const real_t &operator[](int i) const noexcept {
    assert(-1 < i && i < 3);
    return p[i];
  }
  real_t &x() noexcept { return p[0]; }
  real_t &y() noexcept { return p[1]; }
  real_t &z() noexcept { return p[2]; }
  const real_t &x() const noexcept { return p[0]; }
  const real_t &y() const noexcept { return p[1]; }
  const real_t &z() const noexcept { return p[2]; }
  real_t *data() noexcept { return p; }
  const real_t *data() const noexcept { return p; }
  int size() const noexcept { return 3; }

  Point &operator/=(const real_t val) {
    p[0] /= val;
    p[1] /= val;
    p[2] /= val;
    return *this;
  }
  Point &operator+=(const Point &varp) {
    p[0] += varp[0];
    p[1] += varp[1];
    p[2] += varp[2];
    return *this;
  }
};

/**
 * @brief 坐标转换
 *
 */
struct Transform {
  // 新坐标系原点
  Point origin;
  //   新坐标系两个方向
  Point orientx, orienty;

  Transform(const Point &ori, const Point &orix, const Point &oriy)
      : origin{ori}, orientx{orix}, orienty{oriy} {}

  void operator()(const Point &primary, Point &transed) {
    Point tmp;
    tmp[0] = primary[0] - origin[0];
    tmp[1] = primary[1] - origin[1];

    transed[0] = orientx[0] * tmp[0] + orientx[1] * tmp[1];
    transed[1] = orienty[0] * tmp[0] + orienty[1] * tmp[1];
  }
};

void readAirfoil(const string &file_name, vector<Point> &grid);

int findIndex(const vector<Point> &grid, const Point &A);





/**
 * @brief  
 *  编译： g++ -std=c++11 main.cpp -o airfoil.exe
 *  运行： ./airfoil.exe airfoil.dat 0.1070444 0.0078103
 *     
 * 
 * @param argc 
 * @param argv 
 * @return int 
 */
int main(int argc, char *argv[]) {
  if (argc != 4) {
    // cout << argc << endl;
    // cout << argv[0] << endl;
    // cout << argv[1] << endl;
    // 依次是可执行程序  翼型文件名   
    cerr << "./a.out  airfol_file_name  A.x  A.y  " << endl;
    exit(EXIT_FAILURE);
  }
  string airfoil_file_name{argv[1]};
  Point A{atof(argv[2]), atof(argv[3]), 0};
  vector<Point> airfoil_grid;

  readAirfoil(airfoil_file_name, airfoil_grid);

  int index = findIndex(airfoil_grid, A);

  A = airfoil_grid[index];

  int index_p1 = (index + 1) % airfoil_grid.size();
  int index_m1 = (index - 1 + airfoil_grid.size()) % airfoil_grid.size();
  //   计算切向方向
  Point orientx;
  orientx[0] = airfoil_grid[index_p1][0] - airfoil_grid[index_m1][0];
  orientx[1] = airfoil_grid[index_p1][1] - airfoil_grid[index_m1][1];

  double length = sqrt(orientx[0] * orientx[0] + orientx[1] * orientx[1]);
  //   单位化
  orientx[0] /= length;
  orientx[1] /= length;

  // 获得垂线方向
  Point orienty{-orientx[1], orientx[0], 0};

  // 创建转换对象，也可称为函数
  Transform trans(A, orientx, orienty);

  // 输出转换后的结果
  ofstream outf{"output.dat"};
  outf << airfoil_grid.size() << endl;
  Point transed;
  for (int i = 0; i < airfoil_grid.size(); ++i) {

    trans(airfoil_grid[i], transed);
    outf << transed[0] << "  " << transed[1] << "  " << airfoil_grid[i][2]
         << "\n";
  }
  outf.close();

  return 0;
}

/**
 * @brief 读取信息
 *
 * @param file_name
 * @param grid
 */
void readAirfoil(const string &file_name, vector<Point> &grid) {
  ifstream inf{file_name};
  if (!inf) {
    cerr << "open input file err" << endl;
    exit(EXIT_FAILURE);
  }
  cout << "\nstart reading grid file" << endl;

  int npoint;
  inf >> npoint;
  grid.resize(npoint);

  for (int i = 0; i < npoint; ++i) {
    inf >> grid[i][0] >> grid[i][1] >> grid[i][2];
  }
  inf.close();
  cout << "reading grid file success" << endl;
}

/**
 * @brief  找到最接近的点
 *
 * @param grid
 * @param A
 * @return int
 */
int findIndex(const vector<Point> &grid, const Point &A) {
  double distance{1.0e20}, tmp;
  int index{0};
  for (int i = 0; i < grid.size(); ++i) {
    const Point &p{grid[i]};
    tmp = (A[0] - p[0]) * (A[0] - p[0]) + (A[1] - p[1]) * (A[1] - p[1]) +
          (A[2] - p[2]) * (A[2] - p[2]);
    if (tmp < distance) {
      index = i;
      distance = tmp;
    }
  }

  return index;
}
